﻿//////////////////////////////////////////////////////////////////////////////
//This file is part of My Nes                                               //
//A Nintendo Entertainment System Emulator.                                 //
//                                                                          //
//Copyright © 2009 Ala Hadid (AHD)                                          //
//                                                                          //
//My Nes is free software; you can redistribute it and/or modify            //
//it under the terms of the GNU General Public License as published by      //
//the Free Software Foundation; either version 2 of the License, or         //
//(at your option) any later version.                                       //
//                                                                          //
//My Nes is distributed in the hope that it will be useful,                 //
//but WITHOUT ANY WARRANTY; without even the implied warranty of            //
//MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the             //
//GNU General Public License for more details.                              //
//                                                                          //
//You should have received a copy of the GNU General Public License         //
//along with this program; if not, write to the Free Software               //
//Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA//
//////////////////////////////////////////////////////////////////////////////
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;

namespace AHD.MyNes.Nes
{
    /// <summary>
    /// Class of mappers
    /// </summary>
    public class Mappers
    {
        /*
         * IMPORTANT : when you add / update a mapper
         * don't forget to assign it in CartHeaderReader.cs
         * (in SupportedMappersNo & SupportedMapper())
         * to make it available.
         */
        Cart mapperCartridge;
        NesEmulator myEngine;
        public uint[] current_prg_rom_page;
        public uint[] current_chr_rom_page;
        //Mapper #1:
        public int mapper1_register8000BitPosition;
        public int mapper1_registerA000BitPosition;
        public int mapper1_registerC000BitPosition;
        public int mapper1_registerE000BitPosition;
        public int mapper1_register8000Value;
        public int mapper1_registerA000Value;
        public int mapper1_registerC000Value;
        public int mapper1_registerE000Value;
        public byte mapper1_mirroringFlag;
        public byte mapper1_onePageMirroring;
        public byte mapper1_prgSwitchingArea;
        public byte mapper1_prgSwitchingSize;
        public byte mapper1_vromSwitchingSize;

        public int mapper4_commandNumber;
        public int mapper4_prgAddressSelect;
        public int mapper4_chrAddressSelect;

        public byte mapper5_prgBankSize;
        public byte mapper5_chrBankSize;
        public int mapper5_scanlineSplit;
        public bool mapper5_splitIrqEnabled;
        //These are for Mappers 9 and 10
        public byte latch1, latch2;
        public int latch1data1, latch1data2;
        public int latch2data1, latch2data2;

        public byte mapper64_commandNumber;
        public byte mapper64_prgAddressSelect;
        public byte mapper64_chrAddressSelect;
        public bool timer_irq_enabled;
        public bool timer_reload_next;
        public uint timer_irq_count, timer_irq_reload;
        public bool timer_zero_pulse;  //the single pulse timer

        public int mapper32SwitchingMode = 0;
        public ushort timer_irq_counter_16 = 0;
        public ushort timer_irq_Latch_16 = 0;
        public ushort Mapper18_Timer = 0;
        public ushort Mapper18_latch = 0;
        public byte mapper18_control = 0;
        public int Mapper18_IRQWidth = 0;
        public byte Mapper33_Timer , Mapper33_latch = 0;
        public int type = 1;
        public byte[] x = new byte[22];
        public byte Mapper41_CHR_Low = 0;
        public byte Mapper41_CHR_High = 0;
        public byte Mapper225_reg0 = 0xF;
        public byte Mapper225_reg1 = 0xF;
        public byte Mapper225_reg2 = 0xF;
        public byte Mapper225_reg3 = 0xF;

        public byte ReadChrRom(ushort address)
        {
            byte returnvalue = 0xff;

            if (address < 0x400)
            {
                returnvalue = mapperCartridge.chr_rom[current_chr_rom_page[0]][address];
            }
            else if (address < 0x800)
            {
                returnvalue = mapperCartridge.chr_rom[current_chr_rom_page[1]][address - 0x400];
            }
            else if (address < 0xC00)
            {
                returnvalue = mapperCartridge.chr_rom[current_chr_rom_page[2]][address - 0x800];
            }
            else if (address < 0x1000)
            {
                if (mapperCartridge.mapper == 9)
                {
                    if ((address >= 0xfd0) && (address <= 0xfdf))
                    {
                        latch1 = 0xfd;
                        Switch4kChrRom(latch1data1, 1);
                    }
                    else if ((address >= 0xfe0) && (address <= 0xfef))
                    {
                        latch1 = 0xfe;
                        Switch4kChrRom(latch1data2, 1);
                    }
                }
                else if (mapperCartridge.mapper == 10)
                {
                    if ((address >= 0xfd0) && (address <= 0xfdf))
                    {
                        latch1 = 0xfd;
                        Switch4kChrRom(latch1data1, 0);
                    }
                    else if ((address >= 0xfe0) && (address <= 0xfef))
                    {
                        latch1 = 0xfe;
                        Switch4kChrRom(latch1data2, 0);
                    }
                }
                returnvalue = mapperCartridge.chr_rom[current_chr_rom_page[3]][address - 0xC00];
            }
            else if (address < 0x1400)
            {
                returnvalue = mapperCartridge.chr_rom[current_chr_rom_page[4]][address - 0x1000];
            }
            else if (address < 0x1800)
            {
                returnvalue = mapperCartridge.chr_rom[current_chr_rom_page[5]][address - 0x1400];
            }
            else if (address < 0x1C00)
            {
                returnvalue = mapperCartridge.chr_rom[current_chr_rom_page[6]][address - 0x1800];
            }
            else
            {
                if (mapperCartridge.mapper == 9)
                {
                    if ((address >= 0x1fd0) && (address <= 0x1fdf))
                    {
                        latch1 = 0xfd;
                        Switch4kChrRom(latch1data1, 1);
                    }
                    else if ((address >= 0x1fe0) && (address <= 0x1fef))
                    {
                        latch1 = 0xfe;
                        Switch4kChrRom(latch1data2, 1);
                    }
                }
                else if (mapperCartridge.mapper == 10)
                {
                    if ((address >= 0x1fd0) && (address <= 0x1fdf))
                    {
                        latch2 = 0xfd;
                        Switch4kChrRom(latch2data1, 1);
                    }
                    else if ((address >= 0x1fe0) && (address <= 0x1fef))
                    {
                        latch2 = 0xfe;
                        Switch4kChrRom(latch2data2, 1);
                    }
                }
                returnvalue = mapperCartridge.chr_rom[current_chr_rom_page[7]][address - 0x1C00];
            }
            return returnvalue;
        }
        //* 8
        void Switch32kPrgRom(int start)
        {
            int i;
            switch (mapperCartridge.prg_rom_pages)
            {
                case (2): start = (start & 0x7); break;
                case (4): start = (start & 0xf); break;
                case (8): start = (start & 0x1f); break;
                case (16): start = (start & 0x3f); break;
                case (32): start = (start & 0x7f); break;
                case (64): start = (start & 0xff); break;
                case (128): start = (start & 0x1ff); break;
            }
            for (i = 0; i < 8; i++)
            {
                current_prg_rom_page[i] = (uint)(start + i);
            }
        }
        //* 4
        //area 0,1
        void Switch16kPrgRom(int start, int area)
        {
            int i;
            switch (mapperCartridge.prg_rom_pages)
            {
                case (2): start = (start & 0x7); break;
                case (4): start = (start & 0xf); break;
                case (8): start = (start & 0x1f); break;
                case (16): start = (start & 0x3f); break;
                case (32): start = (start & 0x7f); break;
                case (64): start = (start & 0xff); break;
                case (128): start = (start & 0x1ff); break;
            }
            for (i = 0; i < 4; i++)
            {
                current_prg_rom_page[4 * area + i] = (uint)(start + i);
            }
        }
        //* 2
        //area 0,1,2,3
        void Switch8kPrgRom(int start, int area)
        {
            int i;
            switch (mapperCartridge.prg_rom_pages)
            {
                case (2): start = (start & 0x7); break;
                case (4): start = (start & 0xf); break;
                case (8): start = (start & 0x1f); break;
                case (16): start = (start & 0x3f); break;
                case (32): start = (start & 0x7f); break;
                case (64): start = (start & 0xff); break;
                case (128): start = (start & 0x1ff); break;
            }
            for (i = 0; i < 2; i++)
            {
                current_prg_rom_page[2 * area + i] = (uint)(start + i);
            }
        }
        //* 8
        void Switch8kChrRom(int start)
        {
            int i;
            switch (mapperCartridge.chr_rom_pages)
            {
                case (2): start = (start & 0xf); break;
                case (4): start = (start & 0x1f); break;
                case (8): start = (start & 0x3f); break;
                case (16): start = (start & 0x7f); break;
                case (32): start = (start & 0xff); break;
                case (64): start = (start & 0x1ff); break;
            }
            for (i = 0; i < 8; i++)
            {
                current_chr_rom_page[i] = (uint)(start + i);
            }
        }
        //* 4
        //area 0,1
        void Switch4kChrRom(int start, int area)
        {
            int i;
            switch (mapperCartridge.chr_rom_pages)
            {
                case (2): start = (start & 0xf); break;
                case (4): start = (start & 0x1f); break;
                case (8): start = (start & 0x3f); break;
                case (16): start = (start & 0x7f); break;
                case (32): start = (start & 0xff); break;
                case (64): start = (start & 0x1ff); break;
            }
            for (i = 0; i < 4; i++)
            {
                current_chr_rom_page[4 * area + i] = (uint)(start + i);
            }
        }
        //* 2 
        //area 0,1,2,3
        void Switch2kChrRom(int start, int area)
        {
            int i;
            switch (mapperCartridge.chr_rom_pages)
            {
                case (2): start = (start & 0xf); break;
                case (4): start = (start & 0x1f); break;
                case (8): start = (start & 0x3f); break;
                case (16): start = (start & 0x7f); break;
                case (32): start = (start & 0xff); break;
                case (64): start = (start & 0x1ff); break;
            }
            for (i = 0; i < 2; i++)
            {
                current_chr_rom_page[2 * area + i] = (uint)(start + i);
            }
        }
        //area 0,1,2,3,4,5,6,7
        void Switch1kChrRom(int start, int area)
        {
            switch (mapperCartridge.chr_rom_pages)
            {
                case (2): start = (start & 0xf); break;
                case (4): start = (start & 0x1f); break;
                case (8): start = (start & 0x3f); break;
                case (16): start = (start & 0x7f); break;
                case (32): start = (start & 0xff); break;
                case (64): start = (start & 0x1ff); break;
            }
            current_chr_rom_page[area] = (uint)(start);
        }

        public byte ReadPrgRom(ushort address)
        {
            byte returnvalue = 0xff;
            if (address < 0x9000)
            {
                returnvalue = mapperCartridge.prg_rom[current_prg_rom_page[0]][address - 0x8000];
            }
            else if (address < 0xA000)
            {
                returnvalue = mapperCartridge.prg_rom[current_prg_rom_page[1]][address - 0x9000];
            }
            else if (address < 0xB000)
            {
                returnvalue = mapperCartridge.prg_rom[current_prg_rom_page[2]][address - 0xA000];
            }
            else if (address < 0xC000)
            {
                returnvalue = mapperCartridge.prg_rom[current_prg_rom_page[3]][address - 0xB000];
            }
            else if (address < 0xD000)
            {
                returnvalue = mapperCartridge.prg_rom[current_prg_rom_page[4]][address - 0xC000];
            }
            else if (address < 0xE000)
            {
                returnvalue = mapperCartridge.prg_rom[current_prg_rom_page[5]][address - 0xD000];
            }
            else if (address < 0xF000)
            {
                returnvalue = mapperCartridge.prg_rom[current_prg_rom_page[6]][address - 0xE000];
            }
            else
            {
                returnvalue = mapperCartridge.prg_rom[current_prg_rom_page[7]][address - 0xF000];
            }

            return returnvalue;
        }
        public void WriteChrRom(ushort address, byte data)
        {
            if (mapperCartridge.is_vram == true)
            {
                if (address < 0x400)
                {
                    mapperCartridge.chr_rom[current_chr_rom_page[0]][address] = data;
                }
                else if (address < 0x800)
                {
                    mapperCartridge.chr_rom[current_chr_rom_page[1]][address - 0x400] = data;
                }
                else if (address < 0xC00)
                {
                    mapperCartridge.chr_rom[current_chr_rom_page[2]][address - 0x800] = data;
                }
                else if (address < 0x1000)
                {
                    mapperCartridge.chr_rom[current_chr_rom_page[3]][address - 0xC00] = data;
                }
                else if (address < 0x1400)
                {
                    mapperCartridge.chr_rom[current_chr_rom_page[4]][address - 0x1000] = data;
                }
                else if (address < 0x1800)
                {
                    mapperCartridge.chr_rom[current_chr_rom_page[5]][address - 0x1400] = data;
                }
                else if (address < 0x1C00)
                {
                    mapperCartridge.chr_rom[current_chr_rom_page[6]][address - 0x1800] = data;
                }
                else
                {
                    mapperCartridge.chr_rom[current_chr_rom_page[7]][address - 0x1C00] = data;
                }
            }
        }
        public void WritePrgRom(ushort address, byte data)
        {
            #region Mapper # 1
            if (mapperCartridge.mapper == 1)
            {
                //Using Mapper #1
                if ((address >= 0x8000) && (address <= 0x9FFF))
                {
                    if ((data & 0x80) == 0x80)
                    {
                        //Reset
                        mapper1_register8000BitPosition = 0;
                        mapper1_register8000Value = 0;
                        mapper1_mirroringFlag = 0;
                        mapper1_onePageMirroring = 1;
                        mapper1_prgSwitchingArea = 1;
                        mapper1_prgSwitchingSize = 1;
                        mapper1_vromSwitchingSize = 0;
                    }
                    else
                    {
                        mapper1_register8000Value += (data & 0x1) << mapper1_register8000BitPosition;
                        mapper1_register8000BitPosition++;
                        if (mapper1_register8000BitPosition == 5)
                        {
                            mapper1_mirroringFlag = (byte)(mapper1_register8000Value & 0x1);
                            if (mapper1_mirroringFlag == 0)
                            {
                                mapperCartridge.mirroring = MIRRORING.VERTICAL;
                            }
                            else
                            {
                                mapperCartridge.mirroring = MIRRORING.HORIZONTAL;
                            }
                            mapper1_onePageMirroring = (byte)((mapper1_register8000Value >> 1) & 0x1);
                            if (mapper1_onePageMirroring == 0)
                            {
                                mapperCartridge.mirroring = MIRRORING.ONE_SCREEN;
                                mapperCartridge.mirroringBase = 0x2000;
                            }
                            mapper1_prgSwitchingArea = (byte)((mapper1_register8000Value >> 2) & 0x1);
                            mapper1_prgSwitchingSize = (byte)((mapper1_register8000Value >> 3) & 0x1);
                            mapper1_vromSwitchingSize = (byte)((mapper1_register8000Value >> 4) & 0x1);
                            mapper1_register8000BitPosition = 0;
                            mapper1_register8000Value = 0;
                            mapper1_registerA000BitPosition = 0;
                            mapper1_registerA000Value = 0;
                            mapper1_registerC000BitPosition = 0;
                            mapper1_registerC000Value = 0;
                            mapper1_registerE000BitPosition = 0;
                            mapper1_registerE000Value = 0;
                        }
                    }
                }
                else if ((address >= 0xA000) && (address <= 0xBFFF))
                {
                    if ((data & 0x80) == 0x80)
                    {
                        //Reset
                        mapper1_registerA000BitPosition = 0;
                        mapper1_registerA000Value = 0;
                    }
                    else
                    {
                        mapper1_registerA000Value += (data & 0x1) << mapper1_registerA000BitPosition;
                        mapper1_registerA000BitPosition++;
                        if (mapper1_registerA000BitPosition == 5)
                        {
                            if (mapperCartridge.chr_rom_pages > 0)
                            {
                                if (mapper1_vromSwitchingSize == 1)
                                {
                                    Switch4kChrRom(mapper1_registerA000Value * 4, 0);
                                }
                                else
                                {
                                    Switch8kChrRom((mapper1_registerA000Value >> 1) * 8);
                                }
                            }
                            mapper1_registerA000BitPosition = 0;
                            mapper1_registerA000Value = 0;
                        }
                    }
                }
                else if ((address >= 0xC000) && (address <= 0xDFFF))
                {
                    if ((data & 0x80) == 0x80)
                    {
                        //Reset
                        mapper1_registerC000BitPosition = 0;
                        mapper1_registerC000Value = 0;
                    }
                    else
                    {
                        mapper1_registerC000Value += (data & 0x1) << mapper1_registerC000BitPosition;
                        mapper1_registerC000BitPosition++;
                        if (mapper1_registerC000BitPosition == 5)
                        {
                            if (mapperCartridge.chr_rom_pages > 0)
                            {
                                if (mapper1_vromSwitchingSize == 1)
                                {
                                    Switch4kChrRom(mapper1_registerC000Value * 4, 1);
                                }
                            }
                            mapper1_registerC000BitPosition = 0;
                            mapper1_registerC000Value = 0;
                        }
                    }
                }
                else if ((address >= 0xE000) && (address <= 0xFFFF))
                {
                    if ((data & 0x80) == 0x80)
                    {
                        //Reset
                        mapper1_registerE000BitPosition = 0;
                        mapper1_registerE000Value = 0;
                        mapper1_registerA000BitPosition = 0;
                        mapper1_registerA000Value = 0;
                        mapper1_registerC000BitPosition = 0;
                        mapper1_registerC000Value = 0;
                        mapper1_register8000BitPosition = 0;
                        mapper1_register8000Value = 0;
                    }
                    else
                    {
                        mapper1_registerE000Value += (data & 0x1) << mapper1_registerE000BitPosition;
                        mapper1_registerE000BitPosition++;
                        if (mapper1_registerE000BitPosition == 5)
                        {
                            if (mapper1_prgSwitchingSize == 1)
                            {
                                if (mapper1_prgSwitchingArea == 1)
                                {
                                    // Switch bank at 0x8000 and reset 0xC000
                                    Switch16kPrgRom(mapper1_registerE000Value * 4, 0);
                                    Switch16kPrgRom((mapperCartridge.prg_rom_pages - 1) * 4, 1);
                                }
                                else
                                {
                                    // Switch bank at 0xC000 and reset 0x8000
                                    Switch16kPrgRom(mapper1_registerE000Value * 4, 1);
                                    Switch16kPrgRom(0, 0);
                                }
                            }
                            else
                            {
                                //Full 32k switch
                                Switch32kPrgRom((mapper1_registerE000Value >> 1) * 8);
                            }
                            mapper1_registerE000BitPosition = 0;
                            mapper1_registerE000Value = 0;
                        }
                    }
                }
                return;
                //End Mapper #1	
            }
            #endregion
            #region Mapper # 2
            else if (mapperCartridge.mapper == 2)
            {
                if ((address >= 0x8000) && (address <= 0xFFFF))
                {
                    Switch16kPrgRom(data * 4, 0);
                }
                return;
            }
            #endregion
            #region Mapper # 3
            else if (mapperCartridge.mapper == 3)
            {
                if ((address >= 0x8000) && (address <= 0xFFFF))
                {
                    Switch8kChrRom(data * 8);
                }
                return;
            }
            #endregion
            #region Mapper # 4
            else if (mapperCartridge.mapper == 4)
            {
                switch (address)
                {
                    case 0x8000:
                        mapper4_commandNumber = data & 0x7;
                        mapper4_prgAddressSelect = data & 0x40;
                        mapper4_chrAddressSelect = data & 0x80;
                        break;
                    case 0xA000:
                        if ((data & 0x1) == 0)
                        {
                            mapperCartridge.mirroring = MIRRORING.VERTICAL;
                        }
                        else
                        {
                            mapperCartridge.mirroring = MIRRORING.HORIZONTAL;
                        } break;
                    case 0xA001:
                        if ((data & 0x80) == 0)
                            myEngine.isSaveRAMReadonly = true;
                        else
                            myEngine.isSaveRAMReadonly = false;
                        break;
                    case 0xC000: timer_irq_reload = data;
                        if (data == 0)
                        {
                            timer_zero_pulse = true;
                        }
                        timer_reload_next = true;
                        break;
                    case 0xC001: timer_irq_count = data; break;
                    case 0xE000:
                        timer_irq_enabled = false;
                        timer_irq_reload = timer_irq_count;
                        break;
                    case 0xE001: timer_irq_enabled = true; break;
                    case 0x8001:
                        switch (mapper4_commandNumber)
                        {
                            case 0:
                                data = (byte)(data - (data % 2));
                                if (mapper4_chrAddressSelect == 0)
                                {
                                    Switch2kChrRom(data, 0);
                                }
                                else
                                {
                                    Switch2kChrRom(data, 2);
                                }
                                break;
                            case 1:
                                data = (byte)(data - (data % 2));
                                if (mapper4_chrAddressSelect == 0)
                                {
                                    Switch2kChrRom(data, 1);
                                }
                                else
                                {
                                    Switch2kChrRom(data, 3);
                                } break;
                            case 2:
                                data = (byte)(data & (mapperCartridge.chr_rom_pages * 8 - 1));
                                if (mapper4_chrAddressSelect == 0)
                                {
                                    Switch1kChrRom(data, 4);
                                }
                                else
                                {
                                    Switch1kChrRom(data, 0);
                                } break;
                            case 3:
                                if (mapper4_chrAddressSelect == 0)
                                {
                                    Switch1kChrRom(data, 5);
                                }
                                else
                                {
                                    Switch1kChrRom(data, 1);
                                } break;
                            case 4:
                                if (mapper4_chrAddressSelect == 0)
                                {
                                    Switch1kChrRom(data, 6);
                                }
                                else
                                {
                                    Switch1kChrRom(data, 2);
                                } break;
                            case 5:
                                if (mapper4_chrAddressSelect == 0)
                                {
                                    Switch1kChrRom(data, 7);
                                }
                                else
                                {
                                    Switch1kChrRom(data, 3);
                                } break;
                            case 6:
                                if (mapper4_prgAddressSelect == 0)
                                {
                                    Switch8kPrgRom(data * 2, 0);
                                }
                                else
                                {
                                    Switch8kPrgRom(data * 2, 2);
                                }
                                if (mapper4_prgAddressSelect == 0)
                                {
                                    Switch8kPrgRom((mapperCartridge.prg_rom_pages * 4) - 4, 2);
                                }
                                else
                                {
                                    Switch8kPrgRom((mapperCartridge.prg_rom_pages * 4) - 4, 0);
                                }
                                break;
                            case 7: Switch8kPrgRom(data * 2, 1);
                                if (mapper4_prgAddressSelect == 0)
                                {
                                    Switch8kPrgRom((mapperCartridge.prg_rom_pages * 4) - 4, 2);
                                }
                                else
                                {
                                    Switch8kPrgRom((mapperCartridge.prg_rom_pages * 4) - 4, 0);
                                }
                                break;
                        }
                        break;
                }
                return;
            }
            #endregion
            #region Mapper # 5
            else if (mapperCartridge.mapper == 5)
            {
                //Using Mapper #5
                if (address == 0x5100)
                {
                    mapper5_prgBankSize = (byte)(data & 0x3);
                }
                else if (address == 0x5101)
                {
                    mapper5_chrBankSize = (byte)(data & 0x3);
                }
                else if (address == 0x5105)
                {
                }
                else if (address == 0x5114)
                {
                    if (mapper5_prgBankSize == 3)
                    {
                        Switch8kPrgRom((data & 0x7f) * 2, 0);
                    }
                }
                else if (address == 0x5115)
                {
                    if (mapper5_prgBankSize == 1)
                    {
                        Switch16kPrgRom((data & 0x7e) * 2, 0);
                    }
                    else if (mapper5_prgBankSize == 2)
                    {
                        Switch16kPrgRom((data & 0x7e) * 2, 0);
                    }
                    else if (mapper5_prgBankSize == 3)
                    {
                        Switch8kPrgRom((data & 0x7f) * 2, 1);
                    }
                }
                else if (address == 0x5116)
                {
                    if (mapper5_prgBankSize == 2)
                    {
                        Switch8kPrgRom((data & 0x7f) * 2, 2);
                    }
                    else if (mapper5_prgBankSize == 3)
                    {
                        Switch8kPrgRom((data & 0x7f) * 2, 2);
                    }
                }
                else if (address == 0x5117)
                {
                    if (mapper5_prgBankSize == 0)
                    {
                        Switch32kPrgRom((data & 0x7c) * 2);
                    }
                    else if (mapper5_prgBankSize == 1)
                    {
                        Switch16kPrgRom((data & 0x7e) * 2, 1);
                    }
                    else if (mapper5_prgBankSize == 2)
                    {
                        Switch8kPrgRom((data & 0x7f) * 2, 3);
                    }
                    else if (mapper5_prgBankSize == 3)
                    {
                        Switch8kPrgRom((data & 0x7f) * 2, 3);
                    }

                }
                else if (address == 0x5120)
                {
                    if (mapper5_chrBankSize == 3)
                    {
                        Switch1kChrRom(data, 0);
                    }
                }
                else if (address == 0x5121)
                {
                    if (mapper5_chrBankSize == 3)
                    {
                        Switch1kChrRom(data, 1);
                    }
                    else if (mapper5_chrBankSize == 2)
                    {
                        Switch2kChrRom(data, 0);
                    }
                }
                else if (address == 0x5122)
                {
                    if (mapper5_chrBankSize == 3)
                    {
                        Switch1kChrRom(data, 2);
                    }
                }
                else if (address == 0x5123)
                {
                    if (mapper5_chrBankSize == 3)
                    {
                        Switch1kChrRom(data, 3);
                    }
                    else if (mapper5_chrBankSize == 2)
                    {
                        Switch2kChrRom(data, 1);
                    }
                    else if (mapper5_chrBankSize == 1)
                    {
                        Switch4kChrRom(data, 0);
                    }
                }
                else if (address == 0x5124)
                {
                    if (mapper5_chrBankSize == 3)
                    {
                        Switch1kChrRom(data, 4);
                    }
                }
                else if (address == 0x5125)
                {
                    if (mapper5_chrBankSize == 3)
                    {
                        Switch1kChrRom(data, 5);
                    }
                    else if (mapper5_chrBankSize == 2)
                    {
                        Switch2kChrRom(data, 2);
                    }
                }
                else if (address == 0x5126)
                {
                    if (mapper5_chrBankSize == 3)
                    {
                        Switch1kChrRom(data, 6);
                    }
                }
                else if (address == 0x5127)
                {
                    if (mapper5_chrBankSize == 3)
                    {
                        Switch1kChrRom(data, 7);
                    }
                    else if (mapper5_chrBankSize == 2)
                    {
                        Switch2kChrRom(data, 3);
                    }
                    else if (mapper5_chrBankSize == 1)
                    {
                        Switch4kChrRom(data, 1);
                    }
                    else if (mapper5_chrBankSize == 0)
                    {
                        Switch8kChrRom(data);
                    }
                }
                else if (address == 0x5128)
                {
                    Switch1kChrRom(data, 0);
                    Switch1kChrRom(data, 4);
                }
                else if (address == 0x5129)
                {
                    if (mapper5_chrBankSize == 3)
                    {
                        Switch1kChrRom(data, 1);
                        Switch1kChrRom(data, 5);
                    }
                    else if (mapper5_chrBankSize == 2)
                    {
                        Switch2kChrRom(data, 0);
                        Switch2kChrRom(data, 2);
                    }
                }
                else if (address == 0x512a)
                {
                    if (mapper5_chrBankSize == 3)
                    {
                        Switch1kChrRom(data, 2);
                        Switch1kChrRom(data, 6);
                    }
                }
                else if (address == 0x512b)
                {
                    if (mapper5_chrBankSize == 3)
                    {
                        Switch1kChrRom(data, 3);
                        Switch1kChrRom(data, 7);
                    }
                    else if (mapper5_chrBankSize == 2)
                    {
                        Switch2kChrRom(data, 1);
                        Switch2kChrRom(data, 3);
                    }
                    else if (mapper5_chrBankSize == 1)
                    {
                        Switch4kChrRom(data, 0);
                        Switch4kChrRom(data, 1);
                    }
                    else if (mapper5_chrBankSize == 0)
                    {
                        Switch8kChrRom(data);
                    }
                } return;
                //End Mapper #5
            }
            #endregion
            #region Mapper # 7
            else if (mapperCartridge.mapper == 7)
            {
                //Using Mapper #7

                if ((address >= 0x8000) && (address <= 0xFFFF))
                {
                    Switch32kPrgRom((data & 0xf) * 8);
                    if ((data & 0x10) == 0x10)
                    {
                        mapperCartridge.mirroring = MIRRORING.ONE_SCREEN;
                        mapperCartridge.mirroringBase = 0x2400;
                    }
                    else
                    {
                        mapperCartridge.mirroring = MIRRORING.ONE_SCREEN;
                        mapperCartridge.mirroringBase = 0x2000;
                    }
                } return;
                //End Mapper #7
            }
            #endregion
            #region Mapper # 9
            else if (mapperCartridge.mapper == 9)
            {
                //Using Mapper #9
                if ((address >= 0xa000) && (address <= 0xafff))
                {
                    Switch8kPrgRom(data * 2, 0);
                }
                else if ((address >= 0xB000) && (address <= 0xCFFF))
                {
                    Switch4kChrRom(data * 4, 0);
                }
                else if ((address >= 0xD000) && (address <= 0xDFFF))
                {
                    latch1data1 = data * 4;
                }
                else if ((address >= 0xE000) && (address <= 0xEFFF))
                {
                    latch1data2 = data * 4;
                }
                else if ((address >= 0xF000) && (address <= 0xFFFF))
                {
                    if ((data & 1) == 1)
                    {
                        mapperCartridge.mirroring = MIRRORING.HORIZONTAL;
                    }
                    else
                    {
                        mapperCartridge.mirroring = MIRRORING.VERTICAL;
                    }
                } return;
                //End Mapper #9
            }
            #endregion
            #region Mapper # 10
            else if (mapperCartridge.mapper == 10)
            {
                //Using Mapper #10
                if ((address >= 0xa000) && (address <= 0xafff))
                {
                    Switch16kPrgRom(data * 4, 0);
                }
                else if ((address >= 0xB000) && (address <= 0xBFFF))
                {

                    if (latch1 == 0xfd)
                    {
                        Switch4kChrRom(data * 4, 0);
                    }

                    latch1data1 = data * 4;
                }
                else if ((address >= 0xC000) && (address <= 0xCFFF))
                {

                    if (latch1 == 0xfe)
                    {
                        Switch4kChrRom(data * 4, 0);
                    }

                    latch1data2 = data * 4;
                }
                else if ((address >= 0xD000) && (address <= 0xDFFF))
                {

                    if (latch2 == 0xfd)
                    {
                        Switch4kChrRom(data * 4, 1);
                    }

                    latch2data1 = data * 4;
                }
                else if ((address >= 0xE000) && (address <= 0xEFFF))
                {

                    if (latch2 == 0xfe)
                    {
                        Switch4kChrRom(data * 4, 1);
                    }

                    latch2data2 = data * 4;
                }
                else if ((address >= 0xF000) && (address <= 0xFFFF))
                {
                    if ((data & 1) == 1)
                    {
                        mapperCartridge.mirroring = MIRRORING.HORIZONTAL;
                    }
                    else
                    {
                        mapperCartridge.mirroring = MIRRORING.VERTICAL;
                    }
                } return;
                //End Mapper #10
            }
            #endregion
            #region Mapper # 11
            else if (mapperCartridge.mapper == 11)
            {
                //Using Mapper #11

                if ((address >= 0x8000) && (address <= 0xFFFF))
                {
                    int prg_switch;
                    int chr_switch;

                    prg_switch = (data & 0xf);
                    chr_switch = (data >> 4);

                    Switch32kPrgRom(prg_switch * 8);
                    Switch8kChrRom(chr_switch * 8);
                } return;
                //End Mapper #11
            }
            #endregion
            #region Mapper # 13
            else if (mapperCartridge.mapper == 13)
            {
                if ((address >= 0x8000) && (address <= 0xFFFF))
                {
                    //data = (byte)(data - (data % 2));
                    Switch4kChrRom(data * 4, 1);
                }
                return;
            }
            #endregion
            #region Mapper # 15
            else if (mapperCartridge.mapper == 15)
            {
                if ((address >= 0x8000) && (address <= 0xFFFF))
                {
                    byte X = (byte)(data & 0x3F);
                    mapperCartridge.mirroring = ((data & 0x40) == 0) ? MIRRORING.VERTICAL : MIRRORING.HORIZONTAL;
                    byte Y = (byte)(data & 0x80);
                    Y >>= 7;
                    switch (address & 0x3)
                    {
                        case 0://0=32K
                            Switch16kPrgRom(X * 4, 0);
                            Switch16kPrgRom((X + 1) * 4, 1);
                            break;
                        case 1://1=128K
                            Switch16kPrgRom(X * 4, 0);
                            Switch16kPrgRom((mapperCartridge.prg_rom_pages - 1) * 4, 1);
                            break;
                        case 2://2=8K
                            Switch8kPrgRom(((X * 2) + Y) * 2, 0);
                            Switch8kPrgRom(((X * 2) + Y) * 2, 1);
                            Switch8kPrgRom(((X * 2) + Y) * 2, 2);
                            Switch8kPrgRom(((X * 2) + Y) * 2, 3);
                            break;
                        case 3://3=16K
                            Switch16kPrgRom(X * 4, 0);
                            Switch16kPrgRom(X * 4, 1);
                            break;
                    }
                } return;
            }
            #endregion
            #region Mapper # 16
            else if (mapperCartridge.mapper == 16)
            {
                switch (address & 0x000F)
                {
                    case 0: Switch1kChrRom(data, 0); break;
                    case 1: Switch1kChrRom(data, 1); break;
                    case 2: Switch1kChrRom(data, 2); break;
                    case 3: Switch1kChrRom(data, 3); break;
                    case 4: Switch1kChrRom(data, 4); break;
                    case 5: Switch1kChrRom(data, 5); break;
                    case 6: Switch1kChrRom(data, 6); break;
                    case 7: Switch1kChrRom(data, 7); break;
                    case 8: Switch16kPrgRom(data * 4, 0); break;
                    case 9: switch (data & 0x3)
                        {
                            case 0:
                                mapperCartridge.mirroring = MIRRORING.VERTICAL;
                                break;
                            case 1:
                                mapperCartridge.mirroring = MIRRORING.HORIZONTAL;
                                break;
                            case 2:
                                mapperCartridge.mirroring = MIRRORING.ONE_SCREEN;
                                mapperCartridge.mirroringBase = 0x2000;
                                break;
                            case 3:
                                mapperCartridge.mirroring = MIRRORING.ONE_SCREEN;
                                mapperCartridge.mirroringBase = 0x2400;
                                break;
                        } break;
                    case 0xA: timer_irq_enabled = ((data & 0x1) != 0);
                        break;
                    case 0xB:
                        //lowbyte
                        timer_irq_Latch_16 &= 0xFF00; timer_irq_Latch_16 |= data;
                        break;
                    case 0xC:
                        //highbyte
                        timer_irq_Latch_16 &= 0xFF; timer_irq_Latch_16 |= (byte)(data << 8);
                        break;
                    case 0xD: break;//
                }
                return;
            }
            #endregion
            #region Mapper # 18
            else if (mapperCartridge.mapper == 18)
            {
                switch (address)
                {
                    case 0x8000: x[0] = 0; x[0] = (byte)((data & 0x0f)); break;
                    case 0x8001: x[1] = 0; x[1] = (byte)(((data & 0x0f) << 4)|x[0]  ); Switch8kPrgRom((x[1]) * 2, 0); break;
                    case 0x8002: x[2] = 0; x[2] = (byte)((data & 0x0f)); break;
                    case 0x8003: x[3] = 0; x[3] = (byte)( ((data & 0x0f) << 4)|x[2] ); Switch8kPrgRom((x[3]) * 2, 1); break;
                    case 0x9000: x[4] = 0; x[4] = (byte)((data & 0x0f)); break;
                    case 0x9001: x[5] = 0; x[5] = (byte)( ((data & 0x0f) << 4)|x[4] ); Switch8kPrgRom((x[5]) * 2, 2); break;
                    case 0x9002:
                        mapperCartridge.save_ram_present = ((data & 0x1) != 0);
                        myEngine.isSaveRAMReadonly = !mapperCartridge.save_ram_present;
                        break;
                    case 0xA000: x[3] &= 0xf0; x[3] |= (byte)((data & 0x0f)); break;
                    case 0xA001: x[3] &= 0x0f; x[3] |= (byte)((data & 0x0f) << 4); Switch1kChrRom((x[3]), 0); break;
                    case 0xA002: x[4] &= 0xf0; x[4] |= (byte)((data & 0x0f)); break;
                    case 0xA003: x[4] &= 0x0f; x[4] |= (byte)((data & 0x0f) << 4); Switch1kChrRom((x[4]), 1); break;
                    case 0xB000: x[5] &= 0xf0; x[5] |= (byte)((data & 0x0f)); break;
                    case 0xB001: x[5] &= 0x0f; x[5] |= (byte)((data & 0x0f) << 4); Switch1kChrRom((x[5]), 2); break;
                    case 0xB002: x[6] &= 0xf0; x[6] |= (byte)((data & 0x0f)); break;
                    case 0xB003: x[6] &= 0x0f; x[6] |= (byte)((data & 0x0f) << 4); Switch1kChrRom((x[6]), 3); break;
                    case 0xC000: x[7] &= 0xf0; x[7] |= (byte)((data & 0x0f)); break;
                    case 0xC001: x[7] &= 0x0f; x[7] |= (byte)((data & 0x0f) << 4); Switch1kChrRom((x[7]), 4); break;
                    case 0xC002: x[8] &= 0xf0; x[8] |= (byte)((data & 0x0f)); break;
                    case 0xC003: x[8] &= 0x0f; x[8] |= (byte)((data & 0x0f) << 4); Switch1kChrRom((x[8]), 5); break;
                    case 0xD000: x[9] &= 0xf0; x[9] |= (byte)((data & 0x0f)); break;
                    case 0xD001: x[9] &= 0x0f; x[9] |= (byte)((data & 0x0f) << 4); Switch1kChrRom((x[9]), 6); break;
                    case 0xD002: x[10] &= 0xf0; x[10] |= (byte)((data & 0x0f)); break;
                    case 0xD003: x[10] &= 0x0f; x[10] |= (byte)((data & 0x0f) << 4); Switch1kChrRom((x[10]), 7); /*x[10] = 0xff;*/ break;
                    case 0xE000: Mapper18_latch &= 0xFFF0; Mapper18_latch |= (byte)((data & 0x0f)); break;
                    case 0xE001: Mapper18_latch &= 0xFF0f; Mapper18_latch |= (byte)((data & 0x0f) << 4); break;
                    case 0xE002: Mapper18_latch &= 0xF0Ff; Mapper18_latch |= (byte)((data & 0x0f) << 8); break;
                    case 0xE003: Mapper18_latch &= 0x0FFf; Mapper18_latch |= (byte)((data & 0x0f) << 12); break;
                    case 0xF000: timer_irq_enabled = ((data & 0x01) == 0);
                        break;
                    case 0xF001:
                        timer_irq_enabled = ((data & 0x01) != 0);
                        Mapper18_IRQWidth = (data & 0x0E);
                        break;
                    case 0xF002:
                        int BankMode = (address & 0x3);
                        switch (BankMode)
                        {
                            case 0:
                                mapperCartridge.mirroring = MIRRORING.HORIZONTAL;
                                break;
                            case 1:
                                mapperCartridge.mirroring = MIRRORING.VERTICAL;
                                break;
                            case 2:
                            case 3:
                                mapperCartridge.mirroring = MIRRORING.ONE_SCREEN;
                                mapperCartridge.mirroringBase = 0x2000;
                                break;
                        } break;
                }
                switch (Mapper18_IRQWidth)
                {
                    case 0://16 bit
                        break;
                    case 1://12 bit
                        Mapper18_Timer &= 0x0FFF;
                        break;
                    case 2:
                    case 3://8 bit
                        Mapper18_Timer &= 0x00FF;
                        break;
                    case 4:
                    case 5:
                    case 6:
                    case 7://4 bit
                        Mapper18_Timer &= 0x000F;
                        break;
                }
                return;
            }
            #endregion
            #region Mapper # 22
            else if (mapperCartridge.mapper == 22)
            {
                //Using Mapper #22
                if (address == 0x8000)
                {
                    Switch8kPrgRom(data * 2, 0);
                }
                else if (address == 0x9000)
                {
                    switch (data & 0x3)
                    {
                        case (0): mapperCartridge.mirroring = MIRRORING.VERTICAL;
                            break;
                        case (1): mapperCartridge.mirroring = MIRRORING.VERTICAL;
                            break;
                        case (2): mapperCartridge.mirroring = MIRRORING.ONE_SCREEN;
                            mapperCartridge.mirroringBase = 0x2400; break;
                        case (3): mapperCartridge.mirroring = MIRRORING.ONE_SCREEN;
                            mapperCartridge.mirroringBase = 0x2000; break;
                    }
                }
                else if (address == 0xA000)
                {
                    Switch8kPrgRom(data * 2, 1);
                }
                else if (address == 0xB000)
                {
                    Switch1kChrRom((data >> 1), 0);
                }
                else if (address == 0xB001)
                {
                    Switch1kChrRom((data >> 1), 1);
                }
                else if (address == 0xC000)
                {
                    Switch1kChrRom((data >> 1), 2);
                }
                else if (address == 0xC001)
                {
                    Switch1kChrRom((data >> 1), 3);
                }
                else if (address == 0xD000)
                {
                    Switch1kChrRom((data >> 1), 4);
                }
                else if (address == 0xD001)
                {
                    Switch1kChrRom((data >> 1), 5);
                }
                else if (address == 0xE000)
                {
                    Switch1kChrRom((data >> 1), 6);
                }
                else if (address == 0xE001)
                {
                    Switch1kChrRom((data >> 1), 7);
                } return;
                //End Mapper #22
            }
            #endregion
            #region Mapper # 32
            else if (mapperCartridge.mapper == 32)
            {
                switch (address)
                {
                    case 0x9FFF: mapperCartridge.mirroring = ((data & 0x01) == 0) ? MIRRORING.VERTICAL : MIRRORING.HORIZONTAL;
                        mapper32SwitchingMode = ((data & 0x02) == 0) ? 0 : 1;
                        break;
                    case 0x8FFF:
                        if (mapper32SwitchingMode == 0)
                        {
                            Switch8kPrgRom(data * 2, 0);
                        }
                        else
                        {
                            Switch8kPrgRom(data * 2, 2);
                        }
                        break;
                    case 0xAFFF: Switch8kPrgRom(data * 2, 1); break;
                    case 0xBFF0: Switch1kChrRom(data, 0); break;
                    case 0xBFF1: Switch1kChrRom(data, 1); break;
                    case 0xBFF2: Switch1kChrRom(data, 2); break;
                    case 0xBFF3: Switch1kChrRom(data, 3); break;
                    case 0xBFF4: Switch1kChrRom(data, 4); break;
                    case 0xBFF5: Switch1kChrRom(data, 5); break;
                    case 0xBFF6: Switch1kChrRom(data, 6); break;
                    case 0xBFF7: Switch1kChrRom(data, 7); break;
                }
                return;
            }
            #endregion
            #region Mapper # 34
            else if (mapperCartridge.mapper == 34)
            {
                if (address == 0x7ffd)
                {
                    Switch32kPrgRom(data * 8);
                }
                else if (address == 0x7ffe)
                {
                    Switch4kChrRom(data * 4, 0);
                }
                else if (address == 0x7fff)
                {
                    Switch4kChrRom(data * 4, 1);
                }
                else if (address >= 0x8000)
                {
                    Switch32kPrgRom(data * 8);
                }
                return;
            }
            #endregion
            #region Mapper # 41
            else if (mapperCartridge.mapper == 41)
            {
                if (address >= 0x6000 & address <= 0xFFFF)
                {
                    Switch32kPrgRom((address & 0x7) * 8);
                    mapperCartridge.mirroring = ((address & 0x20) == 0) ? MIRRORING.VERTICAL : MIRRORING.HORIZONTAL;
                    Mapper41_CHR_High = (byte)(data & 0x18);
                    Mapper41_CHR_High <<= 3;
                    if ((address & 0x4) == 0)
                    {
                        Mapper41_CHR_Low = (byte)(data & 0x3);
                        //Switch8kChrRom(Mapper41_CHR * 8);
                    }
                    Switch8kChrRom((Mapper41_CHR_High | Mapper41_CHR_Low) * 8);
                }
            }
            #endregion
            #region Mapper # 64
            else if (mapperCartridge.mapper == 64)
            {
                //Using Mapper #64

                if (address == 0x8000)
                {
                    mapper64_commandNumber = data;
                    mapper64_prgAddressSelect = (byte)(data & 0x40);
                    mapper64_chrAddressSelect = (byte)(data & 0x80);
                }
                else if (address == 0x8001)
                {
                    if ((mapper64_commandNumber & 0xf) == 0)
                    {
                        //Swap 2 1k chr roms
                        data = (byte)(data - (data % 2));
                        if (mapper64_chrAddressSelect == 0)
                        {
                            Switch2kChrRom(data, 0);
                        }
                        else
                        {
                            Switch2kChrRom(data, 2);
                        }
                    }
                    else if ((mapper64_commandNumber & 0xf) == 1)
                    {
                        //Swap 2 1k chr roms
                        data = (byte)(data - (data % 2));
                        if (mapper64_chrAddressSelect == 0)
                        {
                            Switch2kChrRom(data, 1);
                        }
                        else
                        {
                            Switch2kChrRom(data, 3);
                        }
                    }
                    else if ((mapper64_commandNumber & 0xf) == 2)
                    {
                        //Swap 1k chr rom
                        if (mapper64_chrAddressSelect == 0)
                        {
                            Switch1kChrRom(data, 4);
                        }
                        else
                        {
                            Switch1kChrRom(data, 0);
                        }
                    }
                    else if ((mapper64_commandNumber & 0xf) == 3)
                    {
                        //Swap 1k chr rom
                        if (mapper64_chrAddressSelect == 0)
                        {
                            Switch1kChrRom(data, 5);
                        }
                        else
                        {
                            Switch1kChrRom(data, 1);
                        }
                    }
                    else if ((mapper64_commandNumber & 0xf) == 4)
                    {
                        //Swap 1k chr rom
                        if (mapper64_chrAddressSelect == 0)
                        {
                            Switch1kChrRom(data, 6);
                        }
                        else
                        {
                            Switch1kChrRom(data, 2);
                        }
                    }
                    else if ((mapper64_commandNumber & 0xf) == 5)
                    {
                        //Swap 1k chr rom
                        if (mapper64_chrAddressSelect == 0)
                        {
                            Switch1kChrRom(data, 7);
                        }
                        else
                        {
                            Switch1kChrRom(data, 3);
                        }
                    }
                    else if ((mapper64_commandNumber & 0xf) == 6)
                    {
                        if (mapper64_prgAddressSelect == 0)
                        {
                            Switch8kPrgRom(data * 2, 0);
                        }
                        else
                        {
                            Switch8kPrgRom(data * 2, 1);
                        }
                    }
                    else if ((mapper64_commandNumber & 0xf) == 7)
                    {
                        if (mapper64_prgAddressSelect == 0)
                        {
                            Switch8kPrgRom(data * 2, 1);
                        }
                        else
                        {
                            Switch8kPrgRom(data * 2, 2);
                        }
                    }
                    else if ((mapper64_commandNumber & 0xf) == 8)
                    {
                        Switch1kChrRom(data, 1);
                    }
                    else if ((mapper64_commandNumber & 0xf) == 9)
                    {
                        Switch1kChrRom(data, 3);
                    }
                    else if ((mapper64_commandNumber & 0xf) == 0xf)
                    {
                        if (mapper64_prgAddressSelect == 0)
                        {
                            Switch8kPrgRom(data * 2, 2);
                        }
                        else
                        {
                            Switch8kPrgRom(data * 2, 0);
                        }
                    }
                }
                else if (address == 0xA000)
                {
                    if ((data & 1) == 1)
                    {
                        mapperCartridge.mirroring = MIRRORING.VERTICAL;
                    }
                    else
                    {
                        mapperCartridge.mirroring = MIRRORING.HORIZONTAL;
                    }

                }

                //End Mapper #64
                return;
            }
            #endregion
            #region Mapper # 66
            else if (mapperCartridge.mapper == 66)
            {
                //Using Mapper #66

                if ((address >= 0x8000) && (address <= 0xFFFF))
                {
                    int prg_switch;
                    int chr_switch;

                    chr_switch = (data & 0x3);
                    prg_switch = (data >> 4) & 0x3;

                    Switch32kPrgRom(prg_switch * 8);
                    Switch8kChrRom(chr_switch * 8);

                } return;
                //End Mapper #66
            }
            #endregion
            #region Mapper # 71
            else if (mapperCartridge.mapper == 71)
            {
                switch (address & 0xF000)
                {
                    case 0xF000:
                    case 0xE000:
                    case 0xD000:
                    case 0xC000: Switch16kPrgRom(data * 4, 0); break;
                    case 0x9000:
                        mapperCartridge.mirroring = MIRRORING.ONE_SCREEN;
                        if ((data & 0x10) != 0)
                        {
                            mapperCartridge.mirroringBase = 0x2000;
                        }
                        else
                        {
                            mapperCartridge.mirroringBase = 0x2400;
                        }
                        break;
                }
                return;
            }
            #endregion
            #region Mapper # 225
            else if (mapperCartridge.mapper == 225)
            {
                //لا تلعب بهالمبر لأنو أي غلطة بيموت
                //Any kiddy hand-play here will kill this mapper
                if ((address >= 0x8000) && (address <= 0xFFFF))
                {
                    int banks = ((address & 0x0040) != 0) ? 1 : 0;
                    ushort wher = (ushort)((address & 0x0Fc0) >> 7);
                    Switch8kChrRom(((address & 0x003F) + (banks << 6)) * 8);
                    if ((address & 0x1000) != 0)//A12
                    {
                        if ((address & 0x0040) != 0)//A6
                        {
                            Switch16kPrgRom((((wher + (banks << 5)) << 1) + 1) * 4, 0);
                            Switch16kPrgRom((((wher + (banks << 5)) << 1) + 1) * 4, 1);
                        }
                        else
                        {
                            Switch16kPrgRom(((wher + (banks << 5)) << 1) * 4, 0);
                            Switch16kPrgRom(((wher + (banks << 5)) << 1) * 4, 1);
                        }
                    }
                    else
                    {
                        Switch32kPrgRom((wher + (banks << 5)) * 8);//ignore A6
                    }
                    mapperCartridge.mirroring = ((address >> 13) & 1) == 0 ? MIRRORING.VERTICAL : MIRRORING.HORIZONTAL;

                }
                if ((address >= 0x5800) && (address <= 0x5FFF))
                {
                    switch (address & 0x3)
                    {
                        case 0: Mapper225_reg0 = (byte)(data & 0xf); break;
                        case 1: Mapper225_reg1 = (byte)(data & 0xf); break;
                        case 2: Mapper225_reg2 = (byte)(data & 0xf); break;
                        case 3: Mapper225_reg3 = (byte)(data & 0xf); break;
                    }
                }
            }
            #endregion
        }
        public void TickTimer_Mapper4()
        {
            if (mapperCartridge.mapper != 4)
            { return; }
            if (myEngine.myPPU.currentScanline < 240)
            {
                //Fixed by Ali Hadid (Croser)
                if (timer_irq_enabled)
                {
                    if ((timer_irq_reload == 0) && timer_reload_next)
                    {
                        myEngine.my6502.Push16(myEngine.my6502.pc_register);
                        myEngine.my6502.PushStatus();
                        myEngine.my6502.pc_register = myEngine.ReadMemory16(0xFFFE);
                        myEngine.my6502.interrupt_flag = 1;
                        timer_irq_reload = timer_irq_count;
                        timer_reload_next = false;
                    }
                    else
                    {
                        if ((myEngine.myPPU.backgroundVisible) || (myEngine.myPPU.spritesVisible))
                            timer_irq_reload = timer_irq_reload - 1;
                    }
                }
            }

        }
        public void TickTimer_Mapper16()
        {
            if (mapperCartridge.mapper != 16)
            { return; }
            if (timer_irq_enabled)
            {
                if (timer_irq_counter_16 ==0)
                {
                    myEngine.my6502.Push16(myEngine.my6502.pc_register);
                    myEngine.my6502.PushStatus();
                    myEngine.my6502.pc_register = myEngine.ReadMemory16(0xFFFE);
                    myEngine.my6502.interrupt_flag = 1;
                    timer_irq_enabled = false;
                    //timer_irq_counter_16 = 0xFFFF;
                    timer_irq_counter_16 = timer_irq_Latch_16;
                }
                else
                { timer_irq_counter_16 -= 1; }
            }
        }
        public void TickTimer_Mapper18()
        {
            if (mapperCartridge.mapper != 18)
            { return; }
            if (timer_irq_enabled)
            {
                if (Mapper18_Timer == 0)
                {
                    myEngine.my6502.Push16(myEngine.my6502.pc_register);
                    myEngine.my6502.PushStatus();
                    myEngine.my6502.pc_register = myEngine.ReadMemory16(0xFFFE);
                    //myEngine.my6502.interrupt_flag = 1;
                    timer_irq_enabled = false;
                    //Mapper18_Timer = Mapper18_latch;
                }
                else
                    Mapper18_Timer -= Mapper18_latch;
            }
        }
        public void TickTimer_Mapper17()
        {
            if (mapperCartridge.mapper != 17)
            { return; }
            if (timer_irq_enabled)
            {

                if (timer_irq_counter_16 == 0xffff)
                {
                    myEngine.my6502.Push16(myEngine.my6502.pc_register);
                    myEngine.my6502.PushStatus();
                    myEngine.my6502.pc_register = myEngine.ReadMemory16(0xFFFE);
                    myEngine.my6502.interrupt_flag = 1;
                    timer_irq_enabled = false;
                    timer_irq_counter_16 = 0;



                }
                else
                    timer_irq_counter_16 += 1;
            }

        }
        public void TickTimer_Mapper33()
        {
            if (mapperCartridge.mapper != 33)
            { return; }
         
                if (timer_irq_enabled)
                {
                    if (Mapper33_Timer == 0xff)
                    {
                        myEngine.my6502.Push16(myEngine.my6502.pc_register);
                        myEngine.my6502.PushStatus();
                        myEngine.my6502.pc_register = myEngine.ReadMemory16(0xFFFE);
                        myEngine.my6502.interrupt_flag = 1;
                        timer_irq_enabled = false;
                       
                    }
                    else
                        timer_irq_counter_16 += 1;
                }
               

        }
        public void SetUpMapperDefaults()
        {
            //uint i;
            Switch32kPrgRom(0);
            if (mapperCartridge.mapper == 41)
            {
                Switch8kChrRom(0);
            }
            if (mapperCartridge.mapper == 34)
            {
                Switch32kPrgRom(0);
                Switch8kChrRom(0);
            }
            if (mapperCartridge.mapper == 33)
            {
                timer_irq_counter_16 = 0x0000;
                timer_irq_Latch_16 = 0x0000;
                timer_irq_enabled = false;
                Mapper33_Timer = 0;
               
            }
            if (mapperCartridge.mapper == 17)
            {
                timer_irq_counter_16 = 0x0000;
                timer_irq_Latch_16 = 0x0000;
                timer_irq_enabled = false;
                Switch32kPrgRom(0);
            }
            if (mapperCartridge.mapper == 225)
            {
                Switch32kPrgRom(0);
                mapperCartridge.mirroring = MIRRORING.VERTICAL;
                Switch8kChrRom(0);
                Mapper225_reg0 = 0xF;
                Mapper225_reg1 = 0xF;
                Mapper225_reg2 = 0xF;
                Mapper225_reg3 = 0xF;
                Switch8kChrRom(0);
            }
            if (mapperCartridge.mapper == 32)
            {
                Switch16kPrgRom(1 * 4, 0);
                Switch16kPrgRom((mapperCartridge.prg_rom_pages - 1) * 4, 1);
                Switch8kChrRom(0);
            }
            if (mapperCartridge.mapper == 13)
            {
                Switch4kChrRom(0, 0);
                Switch8kChrRom(0);
            }
            if (mapperCartridge.mapper == 18)
            {
                timer_irq_counter_16 = 0x0000;
                timer_irq_Latch_16 = 0x0000;
                timer_irq_enabled = false;
                Mapper18_Timer = 0x0000;
                Mapper18_latch = 0x0000;
                Switch16kPrgRom(0, 0);
                Switch16kPrgRom((mapperCartridge.prg_rom_pages - 1) * 4, 1);
                Switch8kChrRom(0);
            }
            if (mapperCartridge.mapper == 16)
            {
                timer_irq_counter_16 = 0x0000;
                timer_irq_Latch_16 = 0x0000;
                timer_irq_enabled = false;
                Switch16kPrgRom(0, 0);
                Switch16kPrgRom((mapperCartridge.prg_rom_pages - 1) * 4, 1);
                Switch8kChrRom(0);
            }
            if (mapperCartridge.mapper == 15)
            {
                //Switch16kPrgRom(1 * 4, 1);
                Switch32kPrgRom(0);
                Switch8kChrRom(0);
            }
            if (mapperCartridge.prg_rom_pages == 1)
            {
                Switch16kPrgRom(0, 1);
                Switch8kChrRom(0);
            }
            else if (mapperCartridge.mapper == 0)
            {
                Switch32kPrgRom(0);
                Switch8kChrRom(0);
            }
            if (mapperCartridge.mapper == 1)
            {
                mapper1_register8000BitPosition = 0;
                mapper1_register8000Value = 0;
                mapper1_mirroringFlag = 0;
                mapper1_onePageMirroring = 1;
                mapper1_prgSwitchingArea = 1;
                mapper1_prgSwitchingSize = 1;
                mapper1_vromSwitchingSize = 0;
                Switch16kPrgRom((mapperCartridge.prg_rom_pages - 1) * 4, 1);
                Switch8kChrRom(0);
            }
            else if (mapperCartridge.mapper == 2)
            {
                Switch16kPrgRom((mapperCartridge.prg_rom_pages - 1) * 4, 1);
                Switch8kChrRom(0);
            }
            else if (mapperCartridge.mapper == 3)
            {
                Switch32kPrgRom(0);
                Switch8kChrRom(0);
            }
            else if (mapperCartridge.mapper == 4)
            {
                mapper4_prgAddressSelect = 0;
                mapper4_chrAddressSelect = 0;
                timer_zero_pulse = false;
                Switch16kPrgRom((mapperCartridge.prg_rom_pages - 1) * 4, 1);
                Switch8kChrRom(0);
            }
            else if (mapperCartridge.mapper == 5)
            {
                Switch8kPrgRom((mapperCartridge.prg_rom_pages * 4) - 2, 0);
                Switch8kPrgRom((mapperCartridge.prg_rom_pages * 4) - 2, 1);
                Switch8kPrgRom((mapperCartridge.prg_rom_pages * 4) - 2, 2);
                Switch8kPrgRom((mapperCartridge.prg_rom_pages * 4) - 2, 3);
                mapper5_splitIrqEnabled = false;
                Switch8kChrRom(0);
            }
            else if (mapperCartridge.mapper == 9)
            {
                latch1 = 0xfe;
                Switch32kPrgRom((mapperCartridge.prg_rom_pages - 1) * 4 - 4);
                Switch8kPrgRom(0, 0);
                Switch8kChrRom(0);
                
            }
            else if (mapperCartridge.mapper == 10)
            {
                Switch16kPrgRom((mapperCartridge.prg_rom_pages - 1) * 4, 1);
                latch1 = 0xfe;
                latch2 = 0xfe;
                Switch8kChrRom(0);
            }
            else if (mapperCartridge.mapper == 22)
            {
                Switch16kPrgRom((mapperCartridge.prg_rom_pages - 1) * 4, 1);
                Switch8kChrRom(0);
            }
            else if (mapperCartridge.mapper == 64)
            {
                Switch8kPrgRom((mapperCartridge.prg_rom_pages * 4) - 2, 0);
                Switch8kPrgRom((mapperCartridge.prg_rom_pages * 4) - 2, 1);
                Switch8kPrgRom((mapperCartridge.prg_rom_pages * 4) - 2, 2);
                Switch8kPrgRom((mapperCartridge.prg_rom_pages * 4) - 2, 3);
                Switch8kChrRom(0);
            }
            else if (mapperCartridge.mapper == 71)
            {
                Switch16kPrgRom((mapperCartridge.prg_rom_pages - 1) * 4, 1);
                Switch8kChrRom(0);
            }
        }
        public Mappers(NesEmulator theEngine, ref Cart theCartridge)
        {
            myEngine = theEngine;
            mapperCartridge = theCartridge;
            current_prg_rom_page = new uint[8];
            current_chr_rom_page = new uint[8];
            timer_irq_enabled = false;
        }
    }
}